"""
书法风格模型
定义不同书法风格的特征标准、权重和评价维度
"""
import os
import json
import numpy as np

# 风格常量定义
STYLE_REGULAR = 'regular'  # 楷书
STYLE_RUNNING = 'running'  # 行书
STYLE_CURSIVE = 'cursive'  # 草书
STYLE_CLERICAL = 'clerical'  # 隶书
STYLE_SEAL = 'seal'  # 篆书

# 支持的风格列表
SUPPORTED_STYLES = [
    STYLE_REGULAR, 
    STYLE_RUNNING, 
    STYLE_CURSIVE, 
    STYLE_CLERICAL, 
    STYLE_SEAL
]

# 风格中文名称映射
STYLE_NAMES = {
    STYLE_REGULAR: '楷书',
    STYLE_RUNNING: '行书',
    STYLE_CURSIVE: '草书',
    STYLE_CLERICAL: '隶书',
    STYLE_SEAL: '篆书'
}

class StyleModel:
    """
    书法风格模型基类
    每种风格都有独特的特征理想值、特征权重和评价维度
    """
    def __init__(self, style_name, model_path=None):
        self.style_name = style_name
        self.model_path = model_path
        # 添加中文名称属性
        self.chinese_name = STYLE_NAMES.get(style_name, '未知风格')
        print(f"初始化 {style_name} 风格模型，中文名称: {self.chinese_name}")
        
        # 设置默认的评价维度
        self.evaluation_dimensions = {
            '笔法': ['curvature', 'angle_distribution', 'line_width_variance'],
            '结构': ['grid_density', 'center_offset', 'component_distribution'],
            '章法': [
                # 原有章法特征
                'structural_complexity', 
                'fourier_descriptors', 
                'wavelet_energy',
                # 新增整篇作品章法特征
                'visual_balance',        # 视觉平衡度
                'spacing_consistency',   # 行列间距一致性
                'space_utilization',     # 空间利用率
                'margin_ratio'           # 边缘留白比例
            ]
        }
        
        # 初始化特征权重和理想特征值
        self._init_feature_weights()
        self._init_ideal_features()
        
        # 风格特定的建议
        self.style_suggestions = {
            'grid_density': {
                'high': '网格密度较高，结构紧凑',
                'medium': '网格密度适中，结构平衡',
                'low': '网格密度较低，结构疏松'
            },
            'center_offset': {
                'high': '字体重心偏移较大',
                'medium': '字体重心偏移适中',
                'low': '字体重心较为居中'
            },
            'component_distribution': {
                'high': '部件分布较为分散',
                'medium': '部件分布较为均衡',
                'low': '部件分布较为集中'
            },
            'curvature': {
                'high': '笔画曲率变化较大',
                'medium': '笔画曲率变化适中',
                'low': '笔画曲率变化较小'
            },
            'angle_distribution': {
                'high': '笔画角度分布较为多变',
                'medium': '笔画角度分布较为均衡',
                'low': '笔画角度分布较为单一'
            },
            'line_width_variance': {
                'high': '笔画宽度变化较大',
                'medium': '笔画宽度变化适中',
                'low': '笔画宽度变化较小'
            },
            'wavelet_energy': {
                'high': '纹理能量分布较为丰富',
                'medium': '纹理能量分布适中',
                'low': '纹理能量分布较为单一'
            },
            'fourier_descriptors': {
                'high': '形状轮廓较为复杂',
                'medium': '形状轮廓适中',
                'low': '形状轮廓较为简单'
            },
            'structural_complexity': {
                'high': '结构复杂度较高',
                'medium': '结构复杂度适中',
                'low': '结构复杂度较低'
            }
        }
    
    def _init_feature_weights(self):
        """初始化特征权重"""
        self.feature_weights = {
            # 原有特征权重
            'grid_density': 0.1,
            'center_offset': 0.1, 
            'component_distribution': 0.1,
            'curvature': 0.1,
            'angle_distribution': 0.1,
            'line_width_variance': 0.1,
            'wavelet_energy': 0.1,
            'fourier_descriptors': 0.1,
            'structural_complexity': 0.1,
            
            # 新增整篇章法特征的权重
            'visual_balance': 0.05,
            'spacing_consistency': 0.05,
            'space_utilization': 0.05,
            'margin_ratio': 0.05
        }
        
        # 确保权重总和为1
        weight_sum = sum(self.feature_weights.values())
        for feature in self.feature_weights:
            self.feature_weights[feature] /= weight_sum
    
    def _init_ideal_features(self):
        """初始化理想特征值，不同风格子类会重写此方法"""
        self.ideal_features = {
            # 使用通用的理想值，每种风格会在子类中重写
            'grid_density': [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
            'center_offset': [0.0, 0.0],
            'component_distribution': [1, 1, 1, 1, 1],
            'curvature': [0.5, 1.0, 1.5, 0.8, 1.2],
            'angle_distribution': [0.125] * 8,
            'line_width_variance': [0.4, 0.6, 0.5],
            'wavelet_energy': [0.125] * 8,
            'fourier_descriptors': [0.05] * 20,
            'structural_complexity': [0.005, 0.01, 0.015],
            
            # 新增整篇章法特征的理想值
            'visual_balance': 0.85,  # 理想的视觉平衡度（0-1，1为完美平衡）
            'spacing_consistency': [0.9, 0.9],  # 理想的行列间距一致性 [行一致性, 列一致性]
            'space_utilization': 0.9,  # 理想的空间利用率（0-1）
            'margin_ratio': [0.1, 0.1, 0.1, 0.1]  # 理想的四周留白比例 [上, 右, 下, 左]
        }
    
    def _load_ideal_features(self):
        """加载风格特定的理想特征值"""
        # 首先尝试从文件加载
        if self.model_path and os.path.exists(self.model_path):
            try:
                with open(self.model_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                pass
        
        # 如果文件不存在或加载失败，返回默认值
        return self._get_default_features()
    
    def _get_default_features(self):
        """获取默认的理想特征值"""
        # 这个方法应该由子类覆盖实现
        return {}
    
    def save_model(self, path=None):
        """保存模型到文件"""
        if path is None:
            path = self.model_path or f"models/{self.style_name}_model.json"
        
        # 确保目录存在
        os.makedirs(os.path.dirname(path), exist_ok=True)
        
        # 保存模型数据
        model_data = {
            'style_name': self.style_name,
            'ideal_features': self.ideal_features,
            'feature_weights': self.feature_weights,
            'evaluation_dimensions': self.evaluation_dimensions
        }
        
        with open(path, 'w', encoding='utf-8') as f:
            json.dump(model_data, f, ensure_ascii=False, indent=2)
        
        return path
    
    def get_style_specific_suggestions(self, feature_name, level):
        """获取风格特定的建议"""
        # 如果特征和级别在建议字典中存在，则返回相应的建议
        if feature_name in self.style_suggestions and level in self.style_suggestions[feature_name]:
            return f"{self.style_suggestions[feature_name][level]}，{STYLE_NAMES.get(self.style_name, '')}风格通常{self.get_style_feature_description(feature_name)}。"
        return ""  # 如果没有找到建议，返回空字符串
    
    def get_style_feature_description(self, feature_name):
        """获取特定风格下特征的描述"""
        # 基础描述，子类可以根据需要重写
        descriptions = {
            'grid_density': '要求结构匀称',
            'center_offset': '注重中宫端正',
            'component_distribution': '强调部件和谐统一',
            'curvature': '有顿挫的曲直变化',
            'angle_distribution': '笔画角度有规律',
            'line_width_variance': '体现笔锋变化',
            'wavelet_energy': '纹理丰富而不杂乱',
            'fourier_descriptors': '轮廓清晰准确',
            'structural_complexity': '结构严谨规范'
        }
        return descriptions.get(feature_name, '需要注意平衡和协调')


class RegularStyleModel(StyleModel):
    """楷书风格模型"""
    def __init__(self, model_path=None):
        super().__init__(STYLE_REGULAR, model_path)
        
        # 重新设置楷书特有的评价维度权重
        self.dimension_weights = {
            '笔法': 0.35,  # 楷书对笔法要求严格
            '结构': 0.35,  # 楷书结构规范
            '章法': 0.30   # 楷书章法相对严谨
        }
        
        # 初始化特征理想值
        self._init_ideal_features()
    
    def _init_ideal_features(self):
        """初始化楷书特有的理想特征值"""
        super()._init_ideal_features()  # 先初始化基础理想值
        
        # 楷书特有的理想特征值
        regular_ideals = {
            'grid_density': [0.15, 0.10, 0.15, 0.10, 0.30, 0.10, 0.15, 0.10, 0.15],  # 中宫饱满
            'center_offset': [0.0, 0.0],  # 中心点位置
            'component_distribution': [120, 140, 160, 140, 120],  # 部件分布均匀
            'curvature': [0.3, 0.5, 0.7, 0.9, 1.1],  # 曲度变化小，笔画规整
            'angle_distribution': [0.15, 0.1, 0.15, 0.1, 0.15, 0.1, 0.15, 0.1],  # 垂直水平笔画占主导
            'line_width_variance': [0.2, 0.3, 0.25],  # 笔画宽度变化较小
            'wavelet_energy': [0.15, 0.15, 0.15, 0.1, 0.1, 0.1, 0.1, 0.15],
            'fourier_descriptors': [0.2, 0.2, 0.15, 0.15, 0.1, 0.1, 0.05, 0.05] + [0.01] * 12,
            'structural_complexity': [0.004, 0.006, 0.008],  # 结构相对简单
            
            # 楷书整篇章法特征理想值
            'visual_balance': 0.90,  # 楷书追求高度平衡
            'spacing_consistency': [0.95, 0.95],  # 楷书行列间距高度一致
            'space_utilization': 0.85,  # 适中的空间利用率
            'margin_ratio': [0.10, 0.10, 0.10, 0.10]  # 均匀的四周留白
        }
        
        # 更新理想特征
        self.ideal_features.update(regular_ideals)

        # 特征权重调整
        self.feature_weights.update({
            # 整篇章法特征在楷书中的权重
            'visual_balance': 0.06,
            'spacing_consistency': 0.06, 
            'space_utilization': 0.06,
            'margin_ratio': 0.06
        })
        
        # 重新归一化权重
        weight_sum = sum(self.feature_weights.values())
        for feature in self.feature_weights:
            self.feature_weights[feature] /= weight_sum


class RunningStyleModel(StyleModel):
    """行书风格模型"""
    def __init__(self, model_path=None):
        super().__init__(STYLE_RUNNING, model_path)
        
        # 重新设置行书特有的评价维度权重
        self.dimension_weights = {
            '笔法': 0.40,  # 行书更注重笔法的流畅性
            '结构': 0.30,  # 结构相对楷书略有变化
            '章法': 0.30   # 章法也很重要
        }
        
        # 初始化特征理想值
        self._init_ideal_features()
    
    def _init_ideal_features(self):
        """初始化行书特有的理想特征值"""
        super()._init_ideal_features()  # 先初始化基础理想值
        
        # 行书特有的理想特征值
        running_ideals = {
            'grid_density': [0.12, 0.12, 0.14, 0.14, 0.20, 0.14, 0.14, 0.12, 0.12],  # 中宫不过分饱满
            'center_offset': [0.02, 0.01],  # 重心略有偏移
            'component_distribution': [130, 150, 170, 150, 130],  # 部件分布略有变化
            'curvature': [0.5, 0.7, 0.9, 1.1, 1.3],  # 曲度变化较大，体现流畅性
            'angle_distribution': [0.12, 0.13, 0.14, 0.13, 0.12, 0.12, 0.12, 0.12],  # 角度分布更加多变
            'line_width_variance': [0.3, 0.4, 0.35],  # 线宽变化更明显
            'wavelet_energy': [0.12, 0.13, 0.14, 0.13, 0.12, 0.12, 0.12, 0.12],
            'fourier_descriptors': [0.18, 0.18, 0.14, 0.14, 0.12, 0.12, 0.06, 0.06] + [0.01] * 12,
            'structural_complexity': [0.006, 0.008, 0.01],  # 结构稍复杂
            
            # 行书整篇章法特征理想值
            'visual_balance': 0.80,  # 行书允许更多的不规则平衡
            'spacing_consistency': [0.85, 0.85],  # 行列间距可以有一定变化
            'space_utilization': 0.80,  # 适中的空间利用率
            'margin_ratio': [0.12, 0.13, 0.12, 0.13]  # 留白可以略有变化
        }
        
        # 更新理想特征
        self.ideal_features.update(running_ideals)

        # 特征权重调整
        self.feature_weights.update({
            # 整篇章法特征在行书中的权重
            'visual_balance': 0.06,
            'spacing_consistency': 0.05, 
            'space_utilization': 0.06,
            'margin_ratio': 0.05
        })
        
        # 重新归一化权重
        weight_sum = sum(self.feature_weights.values())
        for feature in self.feature_weights:
            self.feature_weights[feature] /= weight_sum


class CursiveStyleModel(StyleModel):
    """草书风格模型"""
    def __init__(self, model_path=None):
        super().__init__(STYLE_CURSIVE, model_path)
        
        # 重新设置草书特有的评价维度权重
        self.dimension_weights = {
            '笔法': 0.40,  # 草书笔法极为重要
            '结构': 0.25,  # 结构相对自由
            '章法': 0.35   # 章法感更强，整体感更强
        }
        
        # 初始化特征理想值
        self._init_ideal_features()
    
    def _init_ideal_features(self):
        """初始化草书特有的理想特征值"""
        super()._init_ideal_features()  # 先初始化基础理想值
        
        # 草书特有的理想特征值
        cursive_ideals = {
            'grid_density': [0.10, 0.12, 0.15, 0.12, 0.18, 0.12, 0.15, 0.12, 0.10],  # 中宫适中
            'center_offset': [0.05, 0.02],  # 重心有明显偏移
            'component_distribution': [140, 160, 180, 160, 140],  # 部件分布更加多变
            'curvature': [0.8, 1.0, 1.2, 1.4, 1.6],  # 曲度变化大，体现灵动性
            'angle_distribution': [0.11, 0.14, 0.15, 0.14, 0.11, 0.12, 0.11, 0.12],  # 角度分布更自由
            'line_width_variance': [0.4, 0.6, 0.5],  # 线宽变化明显
            'wavelet_energy': [0.10, 0.12, 0.15, 0.14, 0.13, 0.12, 0.12, 0.12],
            'fourier_descriptors': [0.16, 0.16, 0.13, 0.13, 0.12, 0.12, 0.09, 0.09] + [0.01] * 12,
            'structural_complexity': [0.008, 0.012, 0.016],  # 结构更复杂
            
            # 草书整篇章法特征理想值
            'visual_balance': 0.75,  # 草书允许更多的不规则平衡
            'spacing_consistency': [0.75, 0.75],  # 草书行列间距可以很有变化
            'space_utilization': 0.75,  # 草书空间利用率更自由
            'margin_ratio': [0.15, 0.12, 0.15, 0.12]  # 不均匀的留白
        }
        
        # 更新理想特征
        self.ideal_features.update(cursive_ideals)

        # 特征权重调整
        self.feature_weights.update({
            # 整篇章法特征在草书中的权重
            'visual_balance': 0.07,
            'spacing_consistency': 0.06, 
            'space_utilization': 0.07,
            'margin_ratio': 0.07
        })
        
        # 重新归一化权重
        weight_sum = sum(self.feature_weights.values())
        for feature in self.feature_weights:
            self.feature_weights[feature] /= weight_sum


class ClericalStyleModel(StyleModel):
    """隶书风格模型"""
    def __init__(self, model_path=None):
        super().__init__(STYLE_CLERICAL, model_path)
        
        # 重新设置隶书特有的评价维度权重
        self.dimension_weights = {
            '笔法': 0.30,  # 隶书笔法讲究方正
            '结构': 0.40,  # 结构是隶书的重点
            '章法': 0.30   # 章法均衡
        }
        
        # 初始化特征理想值
        self._init_ideal_features()
    
    def _init_ideal_features(self):
        """初始化隶书特有的理想特征值"""
        super()._init_ideal_features()  # 先初始化基础理想值
        
        # 隶书特有的理想特征值
        clerical_ideals = {
            'grid_density': [0.12, 0.15, 0.12, 0.15, 0.18, 0.15, 0.12, 0.15, 0.12],  # 方正均匀
            'center_offset': [0.01, 0.01],  # 重心适中
            'component_distribution': [150, 170, 190, 170, 150],  # 部件分布均匀
            'curvature': [0.4, 0.6, 0.8, 1.0, 1.2],  # 曲度适中，笔画方正
            'angle_distribution': [0.14, 0.12, 0.14, 0.12, 0.14, 0.12, 0.14, 0.08],  # 垂直水平为主
            'line_width_variance': [0.2, 0.3, 0.25],  # 隶书波磔明显，但变化平稳
            'wavelet_energy': [0.14, 0.14, 0.14, 0.12, 0.12, 0.12, 0.11, 0.11],
            'fourier_descriptors': [0.15, 0.15, 0.13, 0.13, 0.11, 0.11, 0.08, 0.08] + [0.01] * 12,
            'structural_complexity': [0.007, 0.009, 0.011],  # 结构相对简单
            
            # 隶书整篇章法特征理想值
            'visual_balance': 0.85,  # 隶书追求较高平衡度
            'spacing_consistency': [0.90, 0.90],  # 隶书行列间距相当一致
            'space_utilization': 0.85,  # 隶书空间利用率适中
            'margin_ratio': [0.12, 0.12, 0.12, 0.12]  # 留白较为均匀
        }
        
        # 更新理想特征
        self.ideal_features.update(clerical_ideals)

        # 特征权重调整
        self.feature_weights.update({
            # 整篇章法特征在隶书中的权重
            'visual_balance': 0.06,
            'spacing_consistency': 0.07, 
            'space_utilization': 0.06,
            'margin_ratio': 0.06
        })
        
        # 重新归一化权重
        weight_sum = sum(self.feature_weights.values())
        for feature in self.feature_weights:
            self.feature_weights[feature] /= weight_sum


class SealStyleModel(StyleModel):
    """篆书风格模型"""
    def __init__(self, model_path=None):
        super().__init__(STYLE_SEAL, model_path)
        
        # 重新设置篆书特有的评价维度权重
        self.dimension_weights = {
            '笔法': 0.30,  # 篆书笔法讲究均匀圆润
            '结构': 0.35,  # 结构严谨
            '章法': 0.35   # 章法讲究整体美感
        }
        
        # 初始化特征理想值
        self._init_ideal_features()
    
    def _init_ideal_features(self):
        """初始化篆书特有的理想特征值"""
        super()._init_ideal_features()  # 先初始化基础理想值
        
        # 篆书特有的理想特征值
        seal_ideals = {
            'grid_density': [0.12, 0.12, 0.12, 0.12, 0.28, 0.12, 0.12, 0.12, 0.12],  # 中宫饱满
            'center_offset': [0.0, 0.0],  # 重心集中
            'component_distribution': [160, 180, 200, 180, 160],  # 部件分布规整
            'curvature': [0.6, 0.6, 0.6, 0.6, 0.6],  # 曲度均匀，笔画圆润
            'angle_distribution': [0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125],  # 角度分布均匀
            'line_width_variance': [0.1, 0.15, 0.1],  # 线宽变化很小，讲究均匀
            'wavelet_energy': [0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125],
            'fourier_descriptors': [0.14, 0.14, 0.13, 0.13, 0.12, 0.12, 0.11, 0.11] + [0.01] * 12,
            'structural_complexity': [0.005, 0.007, 0.009],  # 结构简洁严谨
            
            # 篆书整篇章法特征理想值
            'visual_balance': 0.95,  # 篆书追求极高的平衡性
            'spacing_consistency': [0.95, 0.95],  # 篆书行列间距高度一致
            'space_utilization': 0.80,  # 篆书空间利用率中等
            'margin_ratio': [0.15, 0.15, 0.15, 0.15]  # 篆书留白较多且均匀
        }
        
        # 更新理想特征
        self.ideal_features.update(seal_ideals)

        # 特征权重调整
        self.feature_weights.update({
            # 整篇章法特征在篆书中的权重
            'visual_balance': 0.07,
            'spacing_consistency': 0.08, 
            'space_utilization': 0.05,
            'margin_ratio': 0.07
        })
        
        # 重新归一化权重
        weight_sum = sum(self.feature_weights.values())
        for feature in self.feature_weights:
            self.feature_weights[feature] /= weight_sum


def get_style_model(style_name=STYLE_REGULAR, model_path=None):
    """
    根据风格名称获取相应的风格模型
    """
    style_models = {
        STYLE_REGULAR: RegularStyleModel,
        STYLE_RUNNING: RunningStyleModel,
        STYLE_CURSIVE: CursiveStyleModel,
        STYLE_CLERICAL: ClericalStyleModel,
        STYLE_SEAL: SealStyleModel
    }
    
    model_class = style_models.get(style_name, RegularStyleModel)
    return model_class(model_path) 